﻿#region Microsoft Public License (Ms-PL)

// Microsoft Public License (Ms-PL)
// 
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
// 
// * Definitions
//      The terms "reproduce," "reproduction," "derivative works," and "distribution" 
//      have the same meaning here as under U.S. copyright law. A "contribution" is 
//      the original software, or any additions or changes to the software. A 
//      "contributor" is any person that distributes its contribution under this license. 
//      "Licensed patents" are a contributor's patent claims that read directly on its 
//      contribution.
// 
// * Grant of Rights
// 
// (A) Copyright Grant- Subject to the terms of this license, including the license 
//      conditions and limitations in section 3, each contributor grants you a non-     
//      exclusive, worldwide, royalty-free copyright license to reproduce its 
//      contribution, prepare derivative works of its contribution, and distribute its 
//      contribution or any derivative works that you create.
// 
// (B) Patent Grant- Subject to the terms of this license, including the license 
//      conditions and limitations in section 3, each contributor grants you a non-
//      exclusive, worldwide, royalty-free license under its licensed patents to make, 
//      have made, use, sell, offer for sale, import, and/or otherwise dispose of its 
//      contribution in the software or derivative works of the contribution in the 
//      software.
// 
// * Conditions and Limitations
// 
// (A) No Trademark License- This license does not grant you rights to use any 
//      contributors' name, logo, or trademarks.
// 
// (B) If you bring a patent claim against any contributor over patents that you 
//      claim are infringed by the software, your patent license from such contributor 
//      to the software ends automatically.
// 
// (C) If you distribute any portion of the software, you must retain all copyright, 
//      patent, trademark, and attribution notices that are present in the software.
// 
// (D) If you distribute any portion of the software in source code form, you may do 
//      so only under this license by including a complete copy of this license with 
//      your distribution. If you distribute any portion of the software in compiled or 
//      object code form, you may only do so under a license that complies with this 
//      license.
// 
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors 
//      give no express warranties, guarantees, or conditions. You may have 
//      additional consumer rights under your local laws which this license cannot 
//      change. To the extent permitted under your local laws, the contributors 
//      exclude the implied warranties of merchantability, fitness for a particular 
//      purpose and non-infringement.

#endregion

using System;
using System.Collections;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Porticle.Generic.TreeStructure.Tests
{
    /// <summary>
    /// Unit Tests.
    /// </summary>
    [TestClass]
    public class UnitTests
    {
        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        [TestMethod]
        public void TestMethod1()
        {
            Country country = new Country();

            var city1 = new City(1);
            country.Children.Add(city1);

            var city2 = new City(2);
            country.Children.Add(city2);

            var city3 = new City(3);
            country.Children.Add(city3);

            var street = new Street();
            city3.Children.Add(street);

            var house1 = new House();
            var house2 = new House();
            var house3 = new House();
            var house4 = new House();
            street.Children.Add(house1);
            street.Children.Add(house2);
            street.Children.Add(house3);
            street.Children.Add(house4);

            int count = 0;

            foreach (City city in country.Children)
            {
                count++;
                Assert.IsTrue(country.Children.Contains(city));
            }

            Assert.IsTrue(count == 3);

            Assert.IsTrue(!city1.IsLastChild);
            Assert.IsTrue(!city2.IsLastChild);
            Assert.IsTrue(city3.IsLastChild);

            Assert.IsTrue(city1.IsFirstChild);
            Assert.IsTrue(!city2.IsFirstChild);
            Assert.IsTrue(!city3.IsFirstChild);

            Assert.IsTrue(city1.NextSibling == city2);
            Assert.IsTrue(city2.NextSibling == city3);

            Assert.IsTrue(city2.PreviousSibling == city1);
            Assert.IsTrue(city3.PreviousSibling == city2);

            Assert.IsTrue(country.FirstChild == city1);
            Assert.IsTrue(country.LastChild == city3);

            Assert.IsTrue(house1.Parent.Parent.Parent == country);

            city3.Parent.Children.Remove(city3);

            Assert.IsTrue(city2.IsLastChild);
            Assert.IsTrue(country.Children.Count == 2);
            Assert.IsTrue(country.LastChild == city2);
            Assert.IsTrue(city1.Parent != null);
            Assert.IsTrue(city2.Parent != null);
            Assert.IsTrue(city3.Parent == null);

            country.Children.Insert(0, city3);

            Assert.IsTrue(city2.IsLastChild);
            Assert.IsTrue(!city1.IsFirstChild);
            Assert.IsTrue(country.Children.Count == 3);
            Assert.IsTrue(country.FirstChild == city3);
            Assert.IsTrue(city1.Parent != null);
            Assert.IsTrue(city2.Parent != null);
            Assert.IsTrue(city3.Parent != null);

            country.Children.RemoveAt(1);

            Assert.IsTrue(city1.Parent == null);
            Assert.IsTrue(city2.Parent != null);
            Assert.IsTrue(city3.Parent != null);

            country.Children.Clear();

            Assert.IsTrue(city1.Parent == null);
            Assert.IsTrue(city2.Parent == null);
            Assert.IsTrue(city3.Parent == null);

            Assert.IsTrue(country.Children.Count == 0);

            country.Children.Add(city1);
            country.Children.Add(city2);
            country.Children.Add(city3);

            Assert.IsTrue(city1.Parent != null);
            Assert.IsTrue(city2.Parent != null);
            Assert.IsTrue(city3.Parent != null);

            var city4 = new City(4);

            Assert.IsTrue(country.Children[0] == city1);
            Assert.IsTrue(country.Children[1] == city2);
            Assert.IsTrue(country.Children[2] == city3);

            country.Children[1] = city4;

            Assert.IsTrue(country.Children[0] == city1);
            Assert.IsTrue(country.Children[1] == city4);
            Assert.IsTrue(country.Children[2] == city3);

            Assert.IsTrue(city1.Parent != null);
            Assert.IsTrue(city2.Parent == null);
            Assert.IsTrue(city3.Parent != null);
            Assert.IsTrue(city4.Parent != null);

            Assert.IsTrue(country.Children.IsReadOnly == false);

            IEnumerator test = ((IEnumerable) country.Children).GetEnumerator();
            count = 0;
            while (test.MoveNext())
            {
                count++;
            }
            Assert.IsTrue(count == 3);

            City[] cities = new City[3];

            country.Children.CopyTo(cities, 0);

            Assert.IsTrue(cities[0] == city1);
            Assert.IsTrue(cities[1] == city4);
            Assert.IsTrue(cities[2] == city3);

            Assert.IsTrue(house1.NextSibling == house2);
            Assert.IsTrue(house2.NextSibling == house3);
            Assert.IsTrue(house3.NextSibling == house4);

            Assert.IsTrue(house2.PreviousSibling == house1);
            Assert.IsTrue(house3.PreviousSibling == house2);
            Assert.IsTrue(house4.PreviousSibling == house3);

            Assert.IsTrue(house1.IsFirstChild);
            Assert.IsTrue(!house2.IsFirstChild);
            Assert.IsTrue(!house3.IsFirstChild);
            Assert.IsTrue(!house4.IsFirstChild);

            Assert.IsTrue(!house1.IsLastChild);
            Assert.IsTrue(!house2.IsLastChild);
            Assert.IsTrue(!house3.IsLastChild);
            Assert.IsTrue(house4.IsLastChild);
        }

        [TestMethod]
        [ExpectedException(typeof (InvalidOperationException))]
        public void TestMethod2()
        {
            Country c = new Country();

            c.Children.Add(new City(1));

            c.FirstChild.FirstChild.ToString();
        }

        [TestMethod]
        [ExpectedException(typeof (InvalidOperationException))]
        public void TestMethod3()
        {
            Country c = new Country();

            c.Children.Add(new City(1));

            c.FirstChild.LastChild.ToString();
        }

        [TestMethod]
        [ExpectedException(typeof (InvalidOperationException))]
        public void TestMethod4()
        {
            Country c1 = new Country();
            Country c2 = new Country();

            var city = new City(1);
            c1.Children.Add(city);

            c2.Children.Add(city);
        }

        [TestMethod]
        [ExpectedException(typeof (InvalidOperationException))]
        public void TestMethod5()
        {
            Country c1 = new Country();

            var city = new City(1);
            c1.Children.Add(city);

            city.Parent = null;

            c1.Children.Remove(city);
        }
    }
}